package com.mh.filter;

import com.google.code.kaptcha.Constants;
import com.mh.entity.CheckCode;
import com.mh.excepsion.KaptchaException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

//验证码校验过滤器
@Component
public class KaptchaFilter extends OncePerRequestFilter {

    //MyAuthNGHandlerImpl实现了AuthenticationFailureHandler接口
    //自定义了登录失败处理器
    @Autowired
    private AuthenticationFailureHandler failureHandler;

    //前端验证码对应参数名
    private String codeParam = "imageCode";

    @Override
    //过滤器的核心方法,用于在请求进入应用之前执行验证码校验逻辑
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        //只有 POST 请求才会触发验证码校验逻辑
        if (request.getMethod().equals("POST")){
            //校验图形验证码是否合法
            try {
                //调用下方具体方法
                validateCode(request);
            } catch (KaptchaException e) {
                //处理验证失败逻辑-->执行自定义登录失败处理器
                failureHandler.onAuthenticationFailure(request,response,e);
            }
        }
        //放行进入下一个过滤器
        filterChain.doFilter(request,response);
    }

    //验证码校验具体方法
    private void validateCode(HttpServletRequest request) {
        //1.获取用户传入的图形验证码
        String reqCode = request.getParameter(this.codeParam);
        if (reqCode == null){
            //避免后续代码出现空指针异常
            //如果前端输入空的话,给转换为空字符串
            reqCode = "";
        }
        //前端传入的验证码非空,去除前后空格
        reqCode = reqCode.trim();

        //2.获取session中的验证码值
        HttpSession session = request.getSession(); //获取session
        //之前在KaptchaController中通过req讲验证码信息存储在session中
        //CheckCode checkCode = new CheckCode(producer.createText());
        //req.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, checkCode);
        CheckCode checkCode = (CheckCode) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);

        //3. 如果Session中存在验证码,则将其移除-->防止验证码被重复使用
        //因为把当初后端生成的验证码信息checkCode已经赋值给当前的checkCode
        //因此,后续的验证码校验也会有验证码信息
        if (checkCode != null){
            session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
        }

        //验证码校验
        //1. 校验验证码是否存在
        if (checkCode == null){
            throw new KaptchaException("验证码不存在");
        }

        //2. 用户输入的验证码reqCode & 后端生成的验证码checkCode.getCode()-->是否一致
        //equalsIgnoreCase(): 忽略大小写比较
        if (! reqCode.equalsIgnoreCase(checkCode.getCode())){
            //如果验证码不匹配,抛出 KaptchaException,提示“验证码输入错误”
            throw new KaptchaException("验证码输入错误");
        }

        //3. 校验验证码是否过期
        if (checkCode.isExpired()){
            throw new KaptchaException("验证码过期");
        }
    }
}
